/* Includes ------------------------------------------------------------------*/
#include "puresun_func.h"
#include "puresun_type.h"
#include "stdbool.h"
#include "stdio.h"

/* Private macro -------------------------------------------------------------*/

/* Private typedef -----------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
 * Function Name : pf_to_upper
 * Function      : make a char to upper
 * Input         : [char *_ch] @_ch: target char
 * Return        : NULL
 * Notes         : this operation will replace source char
 *******************************************************************************/
void pf_to_upper(char *_ch)
{
    if (*_ch >= 'a' && *_ch <= 'z')
        *_ch -= 32;
}

/*******************************************************************************
 * Function Name : pf_to_lower
 * Function      : make a char to lower
 * Input         : [char *_ch] @_ch: target char
 * Return        : NULL
 * Notes         : this operation will replace source char
 *******************************************************************************/
void pf_to_lower(char *_ch)
{
    if (*_ch >= 'A' && *_ch <= 'Z')
        *_ch += 32;
}

/*******************************************************************************
 * Function Name : pf_to_lower_str
 * Function      : make a string to lower
 * Input         : [string str, uint16_t cnt_max]
 *                  @str:       target string
 *                  @cnt_max:   max count of transform
 * Return        : NULL
 * Notes         : this operation will replace source string
 *******************************************************************************/
void pf_to_lower_str(string str, uint16_t cnt_max)
{
    uint16_t cnt = 0;
    do
        pf_to_lower(str);
    while (*++str != 0 && cnt_max != 0 && cnt++ < cnt_max);
}

/*******************************************************************************
 * Function Name : pf_to_upper_str
 * Function      : make a string to upper
 * Input         : [string str, uint16_t cnt_max]
 *                  @str:       target string
 *                  @cnt_max:   max count of transform
 * Return        : NULL
 * Notes         : this operation will replace source string
 *******************************************************************************/
void pf_to_upper_str(string str, uint16_t cnt_max)
{
    uint16_t cnt = 0;
    do
        pf_to_upper(str);
    while (*++str != 0 && cnt_max != 0 && cnt++ < cnt_max);
}

/*******************************************************************************
 * Function Name : pf_str_compare
 * Function      : compare two string until one of them appear a '\0'
 * Input         : [string str1, string str2]
 *                  @str1:  target string 1
 *                  @str2:  target string 2
 * Return        : return true while string 1 and string 2 is not 0, and match a
 *              a '\0' in on of them
 * Notes         : None
 *******************************************************************************/
bool_t pf_str_compare(string str1, string str2)
{
    if (*str1 != 0 && *str2 != 0)
    {
        while (b_true)
        {
            if (*str1++ != *str2++)
            {
                if (*(str1 - 1) != 0 && *(str2 - 1) != 0)
                {
                    return b_false;
                }
                return b_true;
            }
        }
    }
    return b_false;
}

/*******************************************************************************
 * Function Name : pf_char_is_num
 * Function      : determines whether a character is a number
 * Input         : [char _ch]
 * Return        : will be return true if the character is one of 0~9
 * Notes         : None
 *******************************************************************************/
bool_t pf_char_is_num(char _ch)
{
    if (_ch >= '0' && _ch <= '9')
        return b_true;
    return b_false;
}

/*******************************************************************************
 * Function Name : pf_atoi
 * Function      : convert a string to int32 type
 * Input         : [string str] source string
 * Return        : convert result
 * Notes         : support minus number and start with plus character('+') number
 *******************************************************************************/
int32_t pf_atoi(string str)
{
    int32_t num = 0;
    bool_t minus = b_false;
    if (*str == '-')
    {
        minus = b_true;
        str++;
    }
    else if (*str == '+')
    {
        str++;
    }
    while (pf_char_is_num(*str))
        num = num * 10 + *str++ - '0';
    if (minus)
        num = 0 - num;
    return num;
}

/*******************************************************************************
 * Function Name : pf_atol
 * Function      : convert a string to int64 type
 * Input         : [string str] source string
 * Return        : convert result
 * Notes         : support minus number and start with plus character('+') number
 *******************************************************************************/
int64_t pf_atol(string str)
{
    int64_t num = 0;
    bool_t minus = b_false;
    if (*str == '-')
    {
        minus = b_true;
        str++;
    }
    else if (*str == '+')
    {
        str++;
    }
    while (pf_char_is_num(*str))
        num = num * 10 + *str++ - '0';
    if (minus)
        num = 0 - num;
    return num;
}

/*******************************************************************************
 * Function Name: pf_count_char_without_space_newline
 * Description  : count char without space, tab, newline etc.
 * Input        : [byte *buff]
 *
 * Return Value : the count of char without space, tab, newline etc.
 * Note         : none
 *******************************************************************************/
int pf_count_char_without_space_newline(byte *buff)
{
    byte *p = buff;
    int count = 0;
    bool flag = false;
    while (*p)
    {
        if (*p == '"')
        {
            flag = !flag;
        }
        if (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
        {
            count++;
        }
        if (*p == ' ' && flag)
        {
            count++;
        }
        p++;
    }
    return count;
}

/*******************************************************************************
 * Function Name: pf_remove_space_tab_newline
 * Description  : remove space, tab, newline etc.
 * Input        : [byte *in, byte *out]
 *                - in: the buffer to be removed
 *                - out: the buffer to store the result
 *
 * Return Value : none
 * Note         : none
 * Attention    : the caller should allocate enough memory for out and the
 *                memory size of out should be at least the same as in
 *                the caller should free the memory of out after using it
 *                this function will add '\0' at the end of out to make it a
 *                string
 *                in and out can be the same buffer
 *                in will not be changed when this function returns
 *******************************************************************************/
void pf_remove_space_tab_newline(byte *in, byte *out)
{
    byte *p = in;
    byte *q = out;
    bool flag = false;
    while (*p)
    {
        if (*p == '"')
        {
            flag = !flag;
        }
        if (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
        {

            *q = *p;
            q++;
        }
        if (*p == ' ' && flag)
        {
            *q = ' ';
            q++;
        }
        p++;
    }
    *q = '\0';
}

/*******************************************************************************
 * Function Name: pf_str_is_number
 * Description  : check if a string is a number
 * Input        : [string str]
 *                - str: the string to be checked
 * Return Value : b_true: the string is a number
 *                b_false: the string is not a number
 * Note         : none
 * Attention    : none
 *******************************************************************************/
bool_t pf_str_is_number(string str)
{
    if (*str == '-' || *str == '+')
    {
        str++;
    }
    while (*str)
    {
        if (*str < '0' || *str > '9')
        {
            return b_false;
        }
        str++;
    }
    return b_true;
}

/*******************************************************************************
 * Function Name: pf_crc16
 * Description  : calculate crc16
 * Input        : [byte const *p_data, int32_t data_len, uint16_t poly]
 *                - p_data: the data to be calculated
 *                - data_len: the length of data
 *                - poly: the poly of crc16
 * Return Value : the crc16 value
 * Note         : the result endian is determined by the endian of the machine
 * Attention    : none
 *******************************************************************************/
uint16_t pf_crc16(byte const *p_data, int32_t data_len, uint16_t poly)
{
    uint16_t crc_value = 0xFFFF;

    // reverse data poly
    uint16_t poly_rev = 0;
    for (int i = 0; i < 16; i++)
    {
        if (poly & (1 << i))
        {
            poly_rev |= (1 << (15 - i));
        }
    }
    poly = poly_rev;

    while (data_len--)
    {
        crc_value ^= *p_data++;
        for (int i = 0; i < 8; i++)
        {
            if (crc_value & 0x0001)
            {
                crc_value = (crc_value >> 1) ^ poly;
            }
            else
            {
                crc_value >>= 1;
            }
        }
    }

    return crc_value;
}

/*******************************************************************************
 * Function Name: pf_file_exist
 * Description  : check if a file exist
 * Input        : [string path]
 *                - path: the path of the file
 * Return Value : b_true: the file exist
 *                b_false: the file not exist
 * Note         : none
 * Attention    : none
 *******************************************************************************/
bool_t pf_file_exist(string path)
{
    FILE *fp = fopen(path, "r");
    if (fp)
    {
        fclose(fp);
        return b_true;
    }
    return b_false;
}

/************************ (C) COPYRIGHT PURESUN **** END OF FILE ***************/
